<!DOCTYPE html>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<div id="testContainer">
    <div id="outer">
        <div id="inner">
            <div id="innermost"></div>
        </div>
    </div>
</div>
<script>

// TODO(napper): Generate this table from CSSProperties.in.
var independent_properties = [
    // [Property name, [list of valid keywords]]. Each keyword is tested in consecutive pairs.
    ["pointerEvents", ["none", "auto", "stroke", "fill", "painted", "visible", "visiblestroke", "visiblefill", "visiblepainted", "bounding-box", "all"]],
    ["visibility", ["visible", "hidden", "collapse"]],
    ["whiteSpace", ["normal", "pre", "pre-wrap", "pre-line", "nowrap"]],
    ["borderCollapse", ["separate", "collapse"]],
    ["emptyCells", ["show", "hide"]],
    ["captionSide", ["top", "bottom"]],
    ["listStylePosition", ["outside", "inside"]],
    ["webkitBoxDirection", ["normal", "reverse"]],
    ["textTransform", ["capitalize", "uppercase", "lowercase", "none"]],
    ["webkitRtlOrdering", ["logical", "visual"]],
    ["color", ["rgb(255, 0, 0)", "rgb(0, 0, 255)"]],
];

independent_properties.forEach(function(test_data)
{
    var propertyName = test_data[0];
    var keywords = test_data[1];
    var num_keywords = keywords.length;
    // Tests style change propagation for each keyword, verifying there is only a single
    // style recalc.
    for (i = 0; i < num_keywords; i++) {
        var value1 = keywords[i];
        // Use the next keyword in the list, or if it is the last one, wrap around and
        // use the first.
        var value2 = keywords[(i + 1) % num_keywords];

        test(function(t)
        {
            if (!window.internals)
                assert_unreached('This test requires window.internals.');

            // Create a nested div structure for the test.
            var outer = document.createElement("div");
            var inner = document.createElement("div");
            var innermost = document.createElement("div");
            testContainer.appendChild(outer);
            outer.appendChild(inner);
            inner.appendChild(innermost);

            outer.offsetTop; // Force recalc.
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 0);

            // Set the whole container to the first value.
            testContainer.style[propertyName] = value1;

            // All elements start as the first value.
            assert_equals(getComputedStyle(outer)[propertyName], value1);
            assert_equals(getComputedStyle(inner)[propertyName], value1);
            assert_equals(getComputedStyle(innermost)[propertyName], value1);
            outer.offsetTop; // Force recalc.

            // Changing outer also changes inner and innermost.
            outer.style[propertyName] = value2;
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1, "Only outer should be recalced (3 without fast path)");

            assert_equals(getComputedStyle(outer)[propertyName], value2);
            assert_equals(getComputedStyle(inner)[propertyName], value2);
            assert_equals(getComputedStyle(innermost)[propertyName], value2);
            outer.offsetTop; // Force recalc.

            // Changing inner to value1 changes all its children to that value.
            inner.style[propertyName] = value1;
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1, "Only inner should be recalced (2 without fast path)");

            assert_equals(getComputedStyle(outer)[propertyName], value2);
            assert_equals(getComputedStyle(inner)[propertyName], value1);
            assert_equals(getComputedStyle(innermost)[propertyName], value1);
            outer.offsetTop; // Force recalc.

            // Setting inner to value2 and outer to value1 should not propagate value1 to inner.
            inner.style[propertyName] = value2;
            outer.offsetTop; // Force recalc.
            outer.style[propertyName] = value1;
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1, "Only outer should be recalced (2 without fast path)");

            assert_equals(getComputedStyle(outer)[propertyName], value1);
            assert_equals(getComputedStyle(inner)[propertyName], value2);
            assert_equals(getComputedStyle(innermost)[propertyName], value2);
            outer.offsetTop; // Force recalc.

            // Clear for next test.
            outer.remove();
        }, "Changing " + propertyName + ", an independent inherited property, propagates correctly with a single style recalc.");
    }
})
</script>
